using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Tetris
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public static int GAME_WIDTH = 809;
        public static int GAME_HEIGHT = 644;

        private Texture2D _Background;
        private Texture2D _IntroScreen;
        private Texture2D _PauseScreen;
        private Texture2D _GameOverScreen;

        private Playfield _Playfield;

        private GameState currentState = GameState.IntroScreen;

        public bool isPlaying { get { return currentState == GameState.Playing; } }

        public Level currentLevel { get; set; }
        public int rowsFinished { get; set; }
        private SpriteFont gameFont;
        public int CurrentScore { get; set; }

        private Song mainSong;
        private bool mainSongStart = false;

        private Song menuSong;
        private bool menuSongStart = false;

        private Song overSong;
        private bool overSongStart = false;



        private bool isMuted = false;

        public Game()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.PreferredBackBufferHeight = GAME_HEIGHT;
            graphics.PreferredBackBufferWidth = GAME_WIDTH;

            currentLevel = new Level();
        }

        private enum GameState
        {
            IntroScreen,
            Playing,
            Paused,
            GameOver
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            _Playfield = new Playfield(this);
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            _Playfield.LoadContent();
            gameFont = Content.Load<SpriteFont>(@"GameFont");
            InitializeGraphics();

            // music stuff
            mainSong = Content.Load<Song>("sounds/Theme");
            overSong = Content.Load<Song>("sounds/GameOver");
            menuSong = Content.Load<Song>("sounds/Menu");
            MediaPlayer.IsRepeating = true;
        }

        private void InitializeGraphics()
        {
            _Background = Content.Load<Texture2D>("Images/GamePlayBackground");
            _IntroScreen = Content.Load<Texture2D>("Images/IntroScreen");
            _PauseScreen = Content.Load<Texture2D>("Images/PauseScreen");
            _GameOverScreen = Content.Load<Texture2D>("Images/GameOverScreen");
            _Playfield.InitializeGrid();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            
            KeyboardState akeyboard = Keyboard.GetState();

            if (akeyboard.IsKeyDown(Keys.Escape))
            {
                currentState = GameState.Paused;
            }

            UpdateGameObjects(elapsed, akeyboard);

            if (isPlaying)
            {
                _Playfield.Update(gameTime);
            }

            if (isMuted)
            {
                MediaPlayer.Pause();
            }
            else
            {
                if (currentState == GameState.IntroScreen)
                {
                    if (!menuSongStart)
                    {
                        MediaPlayer.Play(menuSong);
                        menuSongStart = true;
                    }
                }
                else if (currentState == GameState.Playing)
                {
                    if (!mainSongStart)
                    {
                        menuSongStart = false;
                        MediaPlayer.Play(mainSong);
                        mainSongStart = true;
                    }
                }
                else if (currentState == GameState.Paused)
                {
                    MediaPlayer.Pause();
                    mainSongStart = false;
                }
                else if (currentState == GameState.GameOver)
                {
                    if (!overSongStart)
                    {
                        mainSongStart = false;
                        MediaPlayer.Play(overSong);
                        overSongStart = true;
                    }
                }
            }
            base.Update(gameTime);
        }

        private void UpdateGameObjects(float elapsed, KeyboardState akeyboard)
        {
            if(akeyboard.IsKeyDown(Keys.Enter))
            {
                if (currentState == GameState.IntroScreen)
                    currentState = GameState.Playing;
                //else if (currentState == GameState.GameOver)
                //    currentState = GameState.Playing;
            }
            if (akeyboard.IsKeyDown(Keys.Escape))
            {
                if (currentState == GameState.Playing)
                    currentState = GameState.Paused;
            }
            if (currentState == GameState.Paused)// or over?
                if (akeyboard.IsKeyDown(Keys.Enter))
                {
                    currentState = GameState.Playing;
                }
            if (currentState == GameState.GameOver)
            {
                if (akeyboard.IsKeyDown(Keys.Enter))
                {
                    _Playfield.InitializeGrid();
                    currentState = GameState.Playing;
                }
            }

            if (akeyboard.IsKeyDown(Keys.M))
                isMuted = true;
            if (akeyboard.IsKeyDown(Keys.U))
            {
                isMuted = false;
                mainSongStart = false;
                overSongStart = false;
                menuSongStart = false;
            }
            
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.White);

            spriteBatch.Begin();

            if (currentState == GameState.IntroScreen)
            {
                spriteBatch.Draw(_IntroScreen, new Rectangle(0, 0, GAME_WIDTH, GAME_HEIGHT), Color.White);
            }
            else if(currentState == GameState.Playing)
            {
                spriteBatch.Draw(_Background, new Rectangle(0, 0, GAME_WIDTH, GAME_HEIGHT), Color.White);
                spriteBatch.DrawString(gameFont, "Level: " + currentLevel.CurrentLevel, new Vector2(60, 300), Color.Black);
                spriteBatch.DrawString(gameFont, "Score: " + CurrentScore, new Vector2(60, 350), Color.Black);
                _Playfield.Draw(gameTime, spriteBatch);
            }
            else if (currentState == GameState.Paused)
            {
                spriteBatch.Draw(_PauseScreen, new Rectangle(0, 0, GAME_WIDTH, GAME_HEIGHT), Color.White * 0.5f);
            }
            else if (currentState == GameState.GameOver)
            {
                spriteBatch.Draw(_GameOverScreen, new Rectangle(0, 0, GAME_WIDTH, GAME_HEIGHT), Color.White);
            }
            

            spriteBatch.End();
            base.Draw(gameTime);
        }

        public void setGameOver(bool isOver)
        {
            if (isOver)
                currentState = GameState.GameOver;
            else if (currentState == GameState.GameOver && !isOver)
                currentState = GameState.Playing;
        }
    }
}
